﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

using Xc.DataAccess.Core;
using Xc.DataAccess.HyperTerminalCore.Services;
using Xc.DataAccess.PcpChannels;
using Xc.DataAccess.Protocoals.PcpChannels.Services;

namespace Xc.Logics.HyperTerminalCore.Udp.Models
{
    /// <summary>
    /// UDP通道
    /// </summary>
    public class UdpChannel : IChannel
    {
        private readonly UdpClientOnlineInfo _udpClientOnlineInfo;

        public UdpChannel(UdpClientOnlineInfo udpClientOnlineInfo)
        {
            _udpClientOnlineInfo = udpClientOnlineInfo;
            _udpClientOnlineInfo.ReceiveMessage += _udpClientOnlineInfo_ReceiveMessage;
        }

        private async void _udpClientOnlineInfo_ReceiveMessage(UdpClientOnlineInfo arg1, byte[] arg2)
        {
            RespondFrame respondFrame = new RespondFrame(arg2);
            switch (respondFrame.MessageCode)
            {
                case MessageCode.UploadUpgradeStatus:
                    {
                        DeviceUploadUpgradeStatusRequest deviceUploadUpgradeStatusRequest = new DeviceUploadUpgradeStatusRequest(arg2);
                        var respond = OnUploadUpgradeStatus?.Invoke(deviceUploadUpgradeStatusRequest);
                        if (respond != null)
                        {
                            var es = await arg1.Send(respond.FullFrame);
                            OnLog?.Invoke(es);
                        }
                    }
                    break;
                case MessageCode.UploadUpdateResult:
                    {
                        DeviceUploadUpdateResultRequest deviceUploadUpdateResultRequest = new DeviceUploadUpdateResultRequest(arg2);
                        var respond = OnUploadUpdateResult?.Invoke(deviceUploadUpdateResultRequest);
                        if (respond != null)
                        {
                            var es = await arg1.Send(respond.FullFrame);
                            OnLog?.Invoke(es);
                        }
                    }
                    break;
                case MessageCode.PackageRequest:
                    {
                        DevicePackageRequest deviceUploadUpdateResultRequest = new DevicePackageRequest(arg2);
                        var respond =await OnDevicePackage?.Invoke(deviceUploadUpdateResultRequest);
                        if (respond != null)
                        {
                            var es = await arg1.Send(respond.FullFrame);
                            OnLog?.Invoke(es);
                        }
                    }
                    break;
                default:
                    break;
            }
        }
        public Action<Result> OnLog;
        /// <summary>
        /// 设备请求升级包
        /// </summary>
        public event Func<DevicePackageRequest,Task<DevicePackageRespond>> OnDevicePackage;
        /// <summary>
        /// 上传升级状态
        /// </summary>
        public event Func<DeviceUploadUpgradeStatusRequest, DeviceUploadUpgradeStatusRespond> OnUploadUpgradeStatus;
        /// <summary>
        /// 上报升级结果
        /// </summary>
        public event Func<DeviceUploadUpdateResultRequest, DeviceUploadUpdateResultRespond> OnUploadUpdateResult;
        /// <summary>
        /// 发起请求
        /// </summary>
        /// <param name="request">发送的数据</param>
        /// <param name="timeout">超时时间</param>
        /// <param name="validateCallBack">校验数据包回调</param>
        /// <returns></returns>
        public async Task<ResultData<byte[]>> Request(byte[] request, TimeSpan timeout, Func<byte[], bool> validateCallBack)
        {
            return await _udpClientOnlineInfo.SendHasRespond(async (client) =>
            {
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();
                try
                {

                    var res = await client.Send(request);
                    if (res.IsSuccess)
                    {
                    AGIN:
                        var respond = validateCallBack?.Invoke(GetResponds(false));
                        if (respond != true)
                        {
                            await Task.Delay(10);
                            if (stopwatch.ElapsedMilliseconds<timeout.TotalMilliseconds)
                            {
                                goto AGIN;
                            }
                            else
                            {
                                return ResultData<byte[]>.Reject($"在{timeout}内未收到有效数据", default);
                            }
                        }
                        else
                        {
                            return ResultData<byte[]>.Accept("校验成功", GetResponds(true));
                        }
                    }
                    else
                    {
                        return ResultData<byte[]>.Reject(res.Message, default);
                    }
                }
                catch (Exception err)
                {
                    return ResultData<byte[]>.Reject(err.Message, default);
                }
                finally
                {
                    stopwatch.Stop();
                }

            });

        }

        public byte[] GetResponds(bool clear)
        {
            return _udpClientOnlineInfo.GetResponds(clear);
        }
    }
}
